TrackCooldowns = LibStub("AceAddon-3.0"):NewAddon("TrackCooldowns", "AceConsole-3.0", "AceComm-3.0", "AceEvent-3.0")

local L = LibStub("AceLocale-3.0"):GetLocale("TrackCooldowns")
local LGIST = LibStub:GetLibrary("LibGroupInSpecT-1.0")

local UnitName = _G.UnitName
local MissingTalentsFor

TrackCooldowns.db = LibStub("AceDB-3.0"):New("TC_DB", nil, "Default")

function TrackCooldowns:OnInitialize()
	self:UnregisterAllEvents()
	self:SetEnabledState(false)
	self.prefix = "TC"
	self:RegisterEvent("PLAYER_LOGIN")
end

function TrackCooldowns:OnEnable()
	self:RegisterComm(self.prefix)
	self:RegisterComm("oRA")
	self:RegisterComm("CTRA")
	self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	--self:RegisterEvent("UNIT_POWER")
	
	local name, module
	for name, module in self:IterateModules() do
		if not module:IsEnabled() then
			self:EnableModule(name)
		end
	end

	self:Print(L["is loaded."])
	self:Print(L["type %s to get help."]:format("|cff66ccff/tc|r"))
end

function TrackCooldowns:OnDisable()
end

--------------[[		Events		]]--------------

function TrackCooldowns:PLAYER_LOGIN()
	self:RegisterEvent("GROUP_ROSTER_UPDATE")
	self:GROUP_ROSTER_UPDATE()
end

do
	local enabled = false

	function TrackCooldowns:GROUP_ROSTER_UPDATE()
		if IsInRaid() and self:GetModule("Display").db.profile.inRaids then
			self:Enable()
			enabled = true
		elseif UnitInBattleground("player") and self:GetModule("Display").db.profile.inBattlegrounds then
			self:Enable()
			enabled = true
		elseif IsInGroup() and self:GetModule("Display").db.profile.inParties then
			self:Enable()
			enabled = true
		elseif IsInGroup() == false and self:GetModule("Display").db.profile.solo then
			self:Enable()
			enabled = true
		elseif not enabled then
			self:Disable()
		end
	end
end

function TrackCooldowns:COMBAT_LOG_EVENT_UNFILTERED(_, timestamp, event, hideCaster, srcGUID, srcName, srcFlags, srcRaidFlags, destGUID, destName, destFlags, destRaidFlags, spellID, spellName, spellSchool, extraSpellID, extraSpellName, extraSpellSchool, auraType)
	if event ~= "SPELL_CAST_SUCCESS" and event ~= "SPELL_RESURRECT" and event ~= "SPELL_AURA_APPLIED" and event ~= "UNIT_DESTROYED" and event ~= "SPELL_SUMMON" then return end
	
	-- Check for totem creation
	if event == "SPELL_CAST_SUCCESS" then
		for k, v in pairs(TrackCooldowns.totems) do
			if v == spellID then
				return
			end
		end
	end
	
	-- Check for totem destruction
	-- Shaman talent "Totemic Restoration" is special. It reduces the CD of totems by a dynamic amount
	if event == "UNIT_DESTROYED" then
		self:GetModule("Display"):HandleTotems(destGUID)
		return
	end

	if not srcName then return end
	if (spellID == 1022 or spellID == 1038 or spellID == 1044 or spellID == 6940) and event == "SPELL_AURA_APPLIED" then return end
	
	local _, c = UnitClass(srcName)
	local playerInfo = LGIST:GetCachedInfo(srcGUID)
	
	-- Certain cooldowns reset other cooldowns, do that here.
	if self.resetCooldowns[spellID] then
		self:GetModule("Display"):ResetCooldown(srcName, spellID)
	end

	-- Check for Unbreakable Spirit cooldown reduction
	if playerInfo and next(playerInfo.talents) and playerInfo.talents[114154] then
		if spellID == 85673 or spellID == 114163 or spellID == 85256 or spellID == 84963 or spellID == 53600 or spellID == 85222 or spellID == 113075 or spellID == 53385 then
			self:GetModule("Display"):HandleUnbreakableSpirit(srcName)
		end
	end
	
	-- Handle healthstones
	if spellID == 6262 and self:GetModule("Display").db.profile.trackHealthstones then
		--self:GetModule("Display"):StartCooldown(srcName, spellID, cooldown, event, destGUID, srcGUID, spells[spellName].duration, spells[spellName].altDuration)
		self:GetModule("Report"):IncrementCooldown(srcName, spellID)
		return
	end
	
	if self.cooldowns[c] then
		local spells = self.cooldowns[c]
		if spells[spellName] then
			local cooldown = spells[spellName].cd

			if spells[spellName].glyph and spells[spellName].altCD then
				if playerInfo and next(playerInfo.glyphs) and playerInfo.glyphs[spells[spellName].glyph] then
					cooldown = spells[spellName].altCD
				end
			end
			
			if spells[spellName].talent and spells[spellName].altCD then
				if playerInfo and next(playerInfo.talents) and playerInfo.talents[spells[spellName].talent] then
					cooldown = spells[spellName].altCD
				end
			end
			
			if spells[spellName].spec and spells[spellName].altCD then
				if playerInfo and playerInfo.global_spec_id == spells[spellName].spec then
					cooldown = spells[spellName].altCD
				end
			end
			
			self:GetModule("Display"):StartCooldown(srcName, spellID, cooldown, event, destGUID, srcGUID, spells[spellName].duration, spells[spellName].altDuration)
			self:GetModule("Report"):IncrementCooldown(srcName, spellID)
			return
		end
	end

	return
end

--------------[[		Comm Methods		]]--------------

function TrackCooldowns:OnCommReceived(prefix, msg, distro, sender)
	if self:GetModule("Display").db.profile.hideSelf and sender == playerName then return end
	if self:GetModule("Display").db.profile.showOwn and sender ~= playerName then return end
	
	local spellId, cooldown = 0, 0
	
	if prefix == "oRA" or prefix == "CTRA" then
		spellId, cooldown = select(3, msg:find("CD (%d) (%d+)"))
		spellId  = tonumber(spellId)
		cooldown = tonumber(cooldown)
		
		if spellId == 0 or cooldown == 0 then return end
		
		local _, c = UnitClass(sender)
		
		if self.cooldowns[c] then
			for k, v in pairs(self.cooldowns[c]) do
				if v.ora and v.ora == spellId then
					spellId = v.id
					self:GetModule("Display"):StartCooldown(sender, spellId, v.cd, "COMM")
					return
				end
			end
		end

	else
		spellId, cooldown = select(3, msg:find("(%d+) (%d+)"))
		spellId  = tonumber(spellId)
		cooldown = tonumber(cooldown)
		
		if cooldown == 0 then
			self:GetModule("Display"):StopCooldown(sender, spellId)
		else
			self:GetModule("Display"):StartCooldown(sender, spellId, cooldown, "COMM")
		end

	end
end

function TrackCooldowns:UpdateHandler(event, guid, unit, info)
	-- Update the talent status
	self:UpdateMissingInspections()

	local fullname = (info.realm and info.name.."-"..info.realm) or info.name
  	if not fullname or not info.class then return end
end
function TrackCooldowns:RemoveHandler(event, guid)
	-- guid no longer a group member
end

function TrackCooldowns:UpdateMissingInspections()
	local guids = LGIST:QueuedInspections()
	local names
	for i, guid in ipairs(guids) do
		local info = LGIST:GetCachedInfo(guid)
    	if info and info.name then
      		names = names and names..", "..info.name or info.name
    	end
  	end
  	
  	MissingTalentsFor = names
end

function TrackCooldowns:tcopy(to, from)
	for k,v in pairs(from) do
		if(type(v) == "table") then
			to[k] = {}
			TrackCooldowns:tcopy(to[k], v);
		else
			to[k] = v;
		end
	end
end

LGIST.RegisterCallback(TrackCooldowns, "GroupInSpecT_Update", "UpdateHandler")
LGIST.RegisterCallback(TrackCooldowns, "GroupInSpecT_Remove", "RemoveHandler")
TrackCooldowns.LGIST = LGIST